﻿using System;
using System.Collections;
using System.Runtime.Serialization;
using System.Text;
using System.Runtime.InteropServices;
using XAMSDK.Types;
using System.IO;

namespace XAMSDK
{
    public class Constants
    {
        public const int XUID_SZ = 80;
        internal const int STRING_SZ = 512;
        internal const bool INPUT_STREAM = false;
        internal const bool OUTPUT_STREAM = true;
        internal const XAMHandle XAM_LIBRARY_HANDLE = (XAMHandle)1;

        // Base level granularity is milliseconds
        public const long RETENTION_SECS = 1000;
        public const long RETENTION_MINS = 60 * RETENTION_SECS;
        public const long RETENTION_HOURS = 60 * RETENTION_MINS;
        public const long RETENTION_DAYS = 24 * RETENTION_HOURS;
        public const long RETENTION_YEARS = 365 * RETENTION_DAYS;

        // Centera specific fields
        public const String CENTERA_APP_NAME = "com.emc.centera.application.name";
        public const String CENTERA_APP_VERSION = "com.emc.centera.application.version";
        public const String CENTERA_NON_AVAIL_TIME = "com.emc.centera.cluster.non.avail.time";
        public const String CENTERA_EMBEDDING_THRESHOLD = "com.emc.centera.embedded.data.threshold";
        public const String CENTERA_MAX_CONNECTIONS = "com.emc.centera.maxconnections";
        public const String CENTERA_MULTICLUSTER_DELETE_STRATEGY = "com.emc.centera.multicluster.delete.strategy";
        public const String CENTERA_MULTICLUSTER_EXISTS_STRATEGY = "com.emc.centera.multicluster.exists.strategy";
        public const String CENTERA_MULTICLUSTER_QUERY_STRATEGY = "com.emc.centera.multicluster.query.strategy";
        public const String CENTERA_MULTICLUSTER_READ_STRATEGY = "com.emc.centera.multicluster.read.strategy";
        public const String CENTERA_MULTICLUSTER_WRITE_STRATEGY = "com.emc.centera.multicluster.write.strategy";
        public const String CENTERA_MULTICLUSTER_DELETE_CLUSTERS = "com.emc.centera.multicluster.delete.clusters";
        public const String CENTERA_MULTICLUSTER_EXISTS_CLUSTERS = "com.emc.centera.multicluster.exists.clusters";
        public const String CENTERA_MULTICLUSTER_QUERY_CLUSTERS = "com.emc.centera.multicluster.query.clusters";
        public const String CENTERA_MULTICLUSTER_READ_CLUSTERS = "com.emc.centera.multicluster.read.clusters";
        public const String CENTERA_MULTICLUSTER_WRITE_CLUSTERS = "com.emc.centera.multicluster.write.clusters";
        public const String CENTERA_OPEN_STRATEGY = "com.emc.centera.open.strategy";
        public const String CENTERA_PROBE_LIMIT = "com.emc.centera.probe.limit";
        public const String CENTERA_RETRY_COUNT= "com.emc.centera.retrycount";
        public const String CENTERA_RETY_SLEEP = "com.emc.centera.retrysleep";

        public const int STRATEGY_NONE = 0;
        public const int STRATEGY_FAILOVER = 1;
        public const int STRATEGY_REPLICATION = 2;

        public const int CLUSTERS_PRIMARY_ONLY = 0;
        public const int CLUSTERS_PRIMARY_AND_ITS_REPLICA = 1;
        public const int CLUSTERS_NO_REPLICAS = 2;
        public const int CLUSTERS_ALL = 3;
        
        public const int OPEN_NORMAL = 0;
        public const int OPEN_LAZY = 1;

        public const String API_LEVEL = ".xam.apiLevel";
        public const String AUTH_DATA_NEEDED_TOKEN = "xam/authentication data needed";
        public const String AUTH_FAILED_TOKEN = "xam/authentication failed";
        public const String AUTH_REQUIRED_TOKEN = "xam/authentication required";
        public const String BAD_XUID_FORMAT_TOKEN = "xam/bad xuid format";
        public const String BOOLEAN_MIME_TYPE = "application/vnd.snia.xam.boolean";
        public const String CONFIG_PATH = ".xam.config.path";
        public const String CONNECT_FAILED_TOKEN = "xam/connection failed";
        public const String DATETIME_MIME_TYPE = "application/vnd.snia.xam.datetime";
        public const String DEFAULT_MIME_TYPE = "application/octet-stream";
        public const String DOUBLE_MIME_TYPE = "application/vnd.snia.xam.double";
        public const String FIELD_EXISTS_TOKEN = "xam/field exists";
        public const String FIELD_IN_USE_TOKEN = "xam/field in use";
        public const String FIELD_IS_READ_ONLY_TOKEN = "xam/field is read only";
        public const String FIELD_NOT_FOUND_TOKEN = "xam/field not found";
        public const String FILESYSTEM_ERROR_TOKEN = "xam/filesystem error";
        public const String IDENTITY = ".xam.identity";
        public const String INT_MIME_TYPE = "application/vnd.snia.xam.int";
        public const String INVALID_FIELD_NAME_TOKEN = "xam/invalid field name";
        public const String INVALID_HANDLE_TOKEN = "xam/invalid handle";
        public const String INVALID_MIME_TYPE_TOKEN = "xam/invalid mime type";
        public const String INVALID_PARAM_TOKEN = "xam/invalid parameter";
        public const String INVALID_POLICY_NAME_TOKEN = "xam/invalid policy name";
        public const String INVALID_XRI_TOKEN = "xam/invalid XRI";
        public const String INVALID_XSET_MODE_TOKEN = "xam/invalid xset mode";
        public const String INVALID_XSTREAM_MODE_TOKEN = "xam/invalid xstream mode";
        public const String JOB_COMMAND = "org.snia.xam.job.command";
        public const String JOB_ERROR = ".xam.job.error";
        public const String JOB_ERRORHEALTH = ".xam.job.errorhealth";
        public const String JOB_ERRORHEALTH_ERROR = "ERROR";
        public const String JOB_ERRORHEALTH_OK = "OK";
        public const String JOB_ERROR_NOT_A_JOB = "org.snia.xam::not_a_job";
        public const String JOB_INSUFFICIENT_PERMISSIONS_TOKEN = "xam/job insufficent permissions";
        public const String JOB_INSUFFICIENT_RESOURCES_TOKEN = "xam/job insufficent resources";
        public const String JOB_INVALID_CMD_SYNTAX_TOKEN = "xam/job invalid command syntax";
        public const String JOB_INVALID_CMD_TOKEN = "xam/job command invalid";
        public const String JOB_LEVEL_NOT_SUPPORTED_TOKEN = "xam/job level not supported";
        public const String JOB_QUERY = "xam.job.query";
        public const String JOB_QUERY_COMMAND = "xam.job.query.command";
        public const String JOB_QUERY_LEVEL = "xam.job.query.level";
        public const String JOB_QUERY_LEVEL_1 = "org.snia.xam.job.query.level.1";
        public const String JOB_QUERY_LEVEL_2 = "org.snia.xam.job.query.level.2";
        public const String JOB_QUERY_RESULTS = "xam.job.query.results";
        public const String JOB_QUERY_RESULTS_COUNT = "xam.job.query.results.count";
        public const String JOB_RUNNING_TOKEN = "xam/job already running";
        public const String JOB_STATUS = ".xam.job.status";
        public const String JOB_STATUS_COMPLETE = "COMPLETE";
        public const String JOB_STATUS_HALTED = "HALTED";
        public const String JOB_STATUS_KILLED = "KILLED";
        public const String JOB_STATUS_NEW = "NEW";
        public const String JOB_STATUS_RUNNING = "RUNNING";
        public const String JOB_STATUS_SHUTTING_DOWN = "SHUTTING DOWN";
        public const String JOB_STATUS_STARTING = "STARTING";
        public const String JOB_STATUS_SUSPENDED = "SUSPENDED";
        public const String LOG_APPEND = ".xam.log.append";
        public const String LOG_COMP_FILTER = ".xam.log.component.filter";
        public const String LOG_FORMAT = ".xam.log.format";
        public const String LOG_LEVEL = ".xam.log.level";
        public const String LOG_MAX_ROLLOVERS = ".xam.log.max.rollovers";
        public const String LOG_MAX_SIZE = ".xam.log.max.size";
        public const String LOG_MSG_FILTER = ".xam.log.message.filter";
        public const String LOG_PATH = ".xam.log.path";
        public const String LOG_VERBOSITY = ".xam.log.verbosity";
        public const String MAX_FIELDS_EXCEEDED_TOKEN = "xam/reached maximum field limit";
        public const String MAX_STRING_FIELD = ".xam.maxstring";
        public const String NOT_A_JOB_TOKEN = "xam/not a job";
        public const String NOT_SUPPORTED_TOKEN = "xam/operation not supported";
        public const String OBJECT_IN_USE_TOKEN = "xam/object in use";
        public const String OK_TOKEN = "xam/OK";
        public const String OPERATION_NOT_ALLOWED_TOKEN = "xam/operation not allowed";
        public const String OUT_OF_MEMORY_TOKEN = "xam/out of memory";
        public const String PARAM_NOT_UTF8_TOKEN = "xam/non-UTF8 parameter";
        public const String PROTOCOL = "snia-xam://";
        public const String QUERY_ERROR_INSUFFICIENT_PERMISSION = "xam.job.query::insufficient_permission";
        public const String QUERY_ERROR_INSUFFICIENT_RESOURCES = "xam.job.query::insufficient_resources";
        public const String QUERY_ERROR_INVALID_CMD_SYNTAX = "xam.job.query::invalid_command_syntax";
        public const String QUERY_ERROR_LEVEL_NOT_SUPPORTED = "xam.job.query::level_not_supported";
        public const String QUERY_ERROR_UNSPECIFIED_CMD = "org.snia.xam.query::unspecified_command";
        public const String QUERY_XUID_LIST_MIME_TYPE = "application/vnd.snia.query.xuid_list";
        public const String STRING_MIME_TYPE = "application/vnd.snia.xam.string";
        public const String TEXT_PLAIN_MIME_TYPE = "text/plain";
        public const String UNKNOWN_ERROR_TOKEN = "xam/unknown error";
        public const String VIM_LIBRARY_TOKEN = "!";
        public const String VIM_LIST = ".xam.vim.list";
        public const String VIM_NOT_FOUND_TOKEN = "xam/vim not found";
        public const String VIM_PATH_ENV_VAR = "XAM_VIM_PATH";
        public const String VIM_SYMBOL_NOT_FOUND_TOKEN = "xam/vim symbol not found";
        public const String XASYNC_HALTED_TOKEN = "xam/async operation halted";
        public const String XASYNC_PENDING_TOKEN = "xam/async operation pending";
        public const String XSET_ABANDONED_TOKEN = "xam/xset abandoned";
        public const String XSET_ACCESS_POLICY = ".xset.access.policy";
        public const String XSET_CORRUPT_TOKEN = "xam/xset corrupted";
        public const String XSET_DELETION_AUTODELETE = ".xset.deletion.autodelete";
        public const String XSET_DELETION_AUTODELETE_POLICY = ".xset.deletion.autodelete.policy";
        public const String XSET_DELETION_SHRED = ".xset.deletion.shred";
        public const String XSET_DELETION_SHRED_POLICY = ".xset.deletion.shred.policy";
        public const String XSET_DIRTY = ".xset.dirty";
        public const String XSET_HOLD = ".xset.hold";
        public const String XSET_HOLD_LIST = ".xset.hold.list";
        public const String XSET_INACCESSIBLE_TOKEN = "xam/xset inaccessible";
        public const String XSET_INVALID_HOLD_ID_TOKEN = "xam/invalid hold id";
        public const String XSET_INVALID_RETENTION_VALUE_TOKEN = "xam/invalid retention value or sequence";
        public const String XSET_MANAGEMENT_POLICY = ".xset.management.policy";
        public const String XSET_MODE_MODIFY = "unrestricted";
        public const String XSET_MODE_READ_ONLY = "readonly";
        public const String XSET_MODE_RESTRICTED = "restricted";
        public const String XSET_RETENTION_BASE_DURATION = ".xset.retention.base.duration";
        public const String XSET_RETENTION_BASE_DURATION_POLICY = ".xset.retention.base.duration.policy";
        public const String XSET_RETENTION_BASE_ENABLED = ".xset.retention.base.enabled";
        public const String XSET_RETENTION_BASE_ENABLED_POLICY = ".xset.retention.base.enabled.policy";
        public const String XSET_RETENTION_BASE_START_TIME = ".xset.retention.base.starttime";
        public const String XSET_RETENTION_EVENT_DURATION = ".xset.retention.event.duration";
        public const String XSET_RETENTION_EVENT_DURATION_POLICY = ".xset.retention.event.duration.policy";
        public const String XSET_RETENTION_EVENT_ENABLED = ".xset.retention.event.enabled";
        public const String XSET_RETENTION_EVENT_ENABLED_POLICY = ".xset.retention.event.enabled.policy";
        public const String XSET_RETENTION_EVENT_START_TIME = ".xset.retention.event.starttime";
        public const String XSET_RETENTION_LIST = ".xset.retention.list";
        public const String XSET_STORAGE_POLICY = ".xset.storage.policy";
        public const String XSET_TIME_ACCESS = ".xset.time.access";
        public const String XSET_TIME_COMMIT = ".xset.time.commit";
        public const String XSET_TIME_CREATION = ".xset.time.creation";
        public const String XSET_TIME_RESIDENCY = ".xset.time.residency";
        public const String XSET_TIME_XUID = ".xset.time.xuid";
        public const String XSET_UNDER_HOLD_TOKEN = "xam/xset is under hold";
        public const String XSET_UNDER_RETENTION_TOKEN = "xam/xset is under retention";
        public const String XSET_XUID = ".xset.xuid";
        public const String XSTREAM_ABANDONED_TOKEN = "xam/xstream abandoned";
        public const String XSTREAM_CORRUPT_TOKEN = "xam/xstream corrupted";
        public const String XSTREAM_MODE_READ_ONLY = "readonly";
        public const String XSTREAM_MODE_WRITEONLY_APPEND = "appendonly";
        public const String XSTREAM_MODE_WRITEONLY_TRUNCATE = "writeonly";
        public const String XSYSTEM_ABANDONED_TOKEN = "xam/xsystem abandoned";
        public const String XSYSTEM_ACCESS = ".xsystem.access";
        public const String XSYSTEM_ACCESS_POLICY_LIST = ".xsystem.access.policy.list";
        public const String XSYSTEM_AUTH_EXPIRATION = ".xsystem.auth.expiration";
        public const String XSYSTEM_AUTH_GRANULE_LIST = ".xsystem.auth.granule.list";
        public const String XSYSTEM_AUTH_IDENTITY_AUTHENTICATION = ".xsystem.auth.identity.authentication";
        public const String XSYSTEM_AUTH_IDENTITY_AUTHORIZATION = ".xsystem.auth.identity.authorization";
        public const String XSYSTEM_AUTODELETE = ".xsystem.deletion.autodelete";
        public const String XSYSTEM_AUTODELETE_POLICY_LIST = ".xsystem.deletion.autodelete.policy.list";
        public const String XSYSTEM_CORRUPT_TOKEN = "xam/xsystem corrupted";
        public const String XSYSTEM_IDENTITY = ".xsystem.identity";
        public const String XSYSTEM_INITIALIZING = ".xsystem.initializing";
        public const String XSYSTEM_JOB_COMMIT_SUPPORTED = ".xsystem.job.commit.supported";
        public const String XSYSTEM_JOB_LIST = ".xsystem.job.list";
        public const String XSYSTEM_JOB_LIST_QUERY = ".xsystem.job.list.xam.job.query";
        public const String XSYSTEM_JOB_QUERY_CONTINUANCE_SUPPORTED = ".xsystem.job.xam.job.query.continuance.supported";
        public const String XSYSTEM_JOB_QUERY_LEVEL1_SUPPORTED = ".xsystem.job.xam.job.query.level1.supported";
        public const String XSYSTEM_JOB_QUERY_LEVEL2_SUPPORTED = ".xsystem.job.xam.job.query.level2.supported";
        public const String XSYSTEM_MANAGEMENT_POLICY_DEFAULT = ".xsystem.management.policy.default";
        public const String XSYSTEM_MANAGEMENT_POLICY_LIST = ".xsystem.management.policy.list";
        public const String XSYSTEM_MAX_FIELDS = ".xsystem.limits.maxFieldsPerXSet";
        public const String XSYSTEM_MAX_SIZE_OF_XSTREAM = ".xsystem.limits.maxSizeOfXStream";
        public const String XSYSTEM_RETENTION_DURATION_POLICY_LIST = ".xsystem.retention.duration.policy.list";
        public const String XSYSTEM_RETENTION_ENABLED_POLICY_LIST = ".xsystem.retention.enabled.policy.list";
        public const String XSYSTEM_SASL_DEFAULT = ".xsystem.auth.SASLmechanism.default";
        public const String XSYSTEM_SASL_LIST = ".xsystem.auth.SASLmechanism.list";
        public const String XSYSTEM_SHRED = ".xsystem.deletion.shred";
        public const String XSYSTEM_SHRED_POLICY_LIST = ".xsystem.deletion.shred.policy.list";
        public const String XSYSTEM_STORAGE_POLICY_LIST = ".xsystem.storage.policy.list";
        public const String XSYSTEM_TIME = ".xsystem.time";
        public const String XUID_MIME_TYPE = "application/vnd.snia.xam.xuid";

        public const long LOG_ALL = (long)(5);
        public const long LOG_INFO = (long)(4);
        public const long LOG_WARN = (long)(3);
        public const long LOG_ERROR = (long)(2);
        public const long LOG_FATAL = (long)(1);
        public const long LOG_OFF = (long)(0);
        public const long XSTREAM_SEEK_SET = (long)(0);
        public const long XSTREAM_SEEK_CUR = (long)(1);
        public const long XSTREAM_SEEK_END = (long)(2);
        public const long XSET_ACCESS_READ_OK = (long)(0x80000000);
        public const long XSET_ACCESS_WRITE_APP_OK = (long)(0x40000000);
        public const long XSET_ACCESS_WRITE_SYSTEM_OK = (long)(0x20000000);
        public const long XSET_ACCESS_CREATE_OK = (long)(0x10000000);
        public const long XSET_ACCESS_DELETE_OK = (long)(0x08000000);
        public const long XSET_ACCESS_HOLD_OK = (long)(0x04000000);
        public const long XSET_ACCESS_RETENTION_EVENT_OK = (long)(0x02000000);
        public const long XSET_ACCESS_JOB_OK = (long)(0x01000000);
        public const long XSET_ACCESS_JOB_COMMIT_OK = (long)(0x00800000);
        public const long XSET_ACCESS_WRITE_OK = (long)(XSET_ACCESS_WRITE_APP_OK | XSET_ACCESS_WRITE_SYSTEM_OK);
        public const long XSET_ACCESS_ALL_OK = (long)(XSET_ACCESS_READ_OK | XSET_ACCESS_WRITE_OK | XSET_ACCESS_CREATE_OK | XSET_ACCESS_DELETE_OK);
    }

    public class Errors
    {
        public const int UNKNOWN_ERROR 							= 1001; // An unknown error occured
        public const int OUT_OF_MEMORY 							= 1002; // Out of memory
        public const int INVALID_PARAM 							= 1003; // Encountered an invalid API parameter
        public const int PARAM_NOT_UTF8 						= 1004; // Parameter found not to be UTF-8
        public const int INVALID_HANDLE 						= 1005; // Invalid handle parameter
        public const int INVALID_MIME_TYPE 						= 1006; // Invalid mime type
        public const int INVALID_XSTREAM_MODE 					= 1007; // Invalid XStream mode
        public const int INVALID_XRI 							= 1008; // Invalid XRI
        public const int INVALID_XSET_MODE 						= 1009; // Invalid operating mode for the XSet
        public const int INVALID_FIELD_NAME 					= 1010; // The specified field name is invalid
        public const int VIM_NOT_FOUND 							= 1011; // VIM could not be located or loaded
        public const int VIM_SYMBOL_NOT_FOUND 					= 1012; // Required symbol not found in VIM
        public const int FIELD_NOT_FOUND 						= 1013; // Field not found for a given handle
        public const int FIELD_IS_READ_ONLY 					= 1014; // Attempted to write to a read only field
        public const int FIELD_EXISTS 							= 1015; // Field already exists
        public const int FIELD_IN_USE 							= 1016; // Field in use error
        public const int MAX_FIELDS_EXCEEDED 					= 1017; // Too many fields exist in this object
        public const int FILESYSTEM_ERROR 						= 1018; // Filesystem error
        public const int XSYSTEM_ABANDONED 						= 1019; // The XSystem instance has been abandoned
        public const int XSET_ABANDONED 						= 1020; // The XSet instance has been abandoned
        public const int XSTREAM_ABANDONED 						= 1021; // The XStream instance has been abandoned
        public const int XSYSTEM_CORRUPT 						= 1022; // The XSystem instance has been corrupted
        public const int XSET_CORRUPT 							= 1023; // The XSet instance has been corrupted
        public const int XSTREAM_CORRUPT 						= 1024; // The XStream instance has been corrupted
        public const int CONNECT_FAILED 						= 1025; // Failed to connect to the XSystem
        public const int AUTH_REQUIRED 							= 1026; // Authentication is required
        public const int AUTH_DATA_NEEDED 						= 1027; // Additional authentication data is required
        public const int AUTH_FAILED 							= 1028; // Authentication failed
        public const int BAD_XUID_FORMAT 						= 1029; // Bad XUD format
        public const int XSET_INACCESSIBLE 						= 1030; // The XSet was inaccessible
        public const int XASYNC_PENDING 						= 1031; // Asynchronous operation is pending
        public const int NOT_SUPPORTED 							= 1032; // The operation requested is not supported
        public const int OPERATION_NOT_ALLOWED 					= 1033; // Operation not allowed
        public const int OBJECT_IN_USE 							= 1034; // This object is currently in use
        public const int NOT_A_JOB 								= 1035; // The XSet does not contain a job request
        public const int JOB_INVALID_CMD 						= 1036; // The job command is invalid 
        public const int JOB_INVALID_CMD_SYNTAX 				= 1037; // The job command syntax is invalid
        public const int JOB_LEVEL_NOT_SUPPORTED 				= 1038; // The job level is insufficent
        public const int JOB_INSUFFICIENT_PERMISSIONS			= 1039; // The job permissions are insuffient
        public const int JOB_INSUFFICIENT_RESOURCES 			= 1040; // The job resources are insufficent
        public const int JOB_RUNNING 							= 1041; // A job is already running
        public const int XSET_UNDER_RETENTION 					= 1042; // The XSet is under retention
        public const int XSET_UNDER_HOLD 						= 1043; // The XSet is under hold and cannot be deleted
        public const int XSET_INVALID_HOLD_ID 					= 1044; // The hold id is invalid
        public const int XSET_INVALID_RETENTION_VALUE 			= 1045; // Invalid retention value or sequence
        public const int INVALID_POLICY_NAME 					= 1046; // Invalid policy name for this operation
        public const int XASYNC_HALTED 							= 1047; // The async operation was halted
    }
    internal sealed class Imports
    {
        [DllImport("xam.dll")]
        public static extern int XAMLibrary_Connect(string inConnectString, out XSystemHandle outXSystem);

        [DllImport("xam.dll")]
        [return: MarshalAs(UnmanagedType.U1)] 
        public static extern bool XAM_GetErrorToken(XAMHandle inHandle, int inStatus, StringBuilder outToken);

        [DllImport("xam.dll")]
        public static extern int XAM_OpenFieldIterator(XAMHandle inHandle, string inPattern, out XIteratorHandle outIterator);

        [DllImport("xam.dll")]
        public static extern int XAM_ContainsField(XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] out bool outContained);

        [DllImport("xam.dll")]
        public static extern int XAM_SetFieldAsBinding(XAMHandle inHandle, string inName);

        [DllImport("xam.dll")]
        public static extern int XAM_SetFieldAsNonbinding(XAMHandle inHandle, string inName);

        [DllImport("xam.dll")]
        public static extern int XAM_GetFieldType (XAMHandle inHandle, string inName, StringBuilder outType);

        [DllImport("xam.dll")]
        public static extern int XAM_GetFieldLength (XAMHandle inHandle, string inName, out long outLength);
        
        [DllImport("xam.dll")]
        public static extern int XAM_GetFieldBinding (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] out bool outBinding);
        
        [DllImport("xam.dll")]
        public static extern int XAM_GetFieldReadOnly (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] out bool outReadOnly);

        [DllImport("xam.dll")]
        public static extern int XAM_DeleteField (XAMHandle inHandle, string inName);
        
        [DllImport("xam.dll")]
        public static extern int XAM_CreateBoolean (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] bool inBinding, [MarshalAs(UnmanagedType.U1)] bool inValue);

        [DllImport("xam.dll")]
        public static extern int XAM_CreateInt (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] bool inBinding, long inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_CreateDouble (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] bool inBinding, double inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_CreateXUID(XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] bool inBinding, byte[] inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_CreateString (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_CreateDatetime(XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] bool inBinding, StringBuilder inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_SetBoolean (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] bool inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_SetInt (XAMHandle inHandle, string inName, long inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_SetDouble (XAMHandle inHandle, string inName, double inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_SetXUID(XAMHandle inHandle, string inName, byte[] inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_SetString (XAMHandle inHandle, string inName, string inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_SetDatetime(XAMHandle inHandle, string inName, StringBuilder inValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_GetBoolean (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] out bool outValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_GetInt (XAMHandle inHandle, string inName, out long outValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_GetDouble (XAMHandle inHandle, string inName, out double outValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_GetXUID(XAMHandle inHandle, string inName, byte[] outValue);
        
        [DllImport("xam.dll")]
        public static extern int XAM_GetString(XAMHandle inHandle, string inName, byte[] outValue);

        [DllImport("xam.dll")]
        public static extern int XAM_GetString(XAMHandle inHandle, string inName, StringBuilder outValue);

        [DllImport("xam.dll")]
        public static extern int XAM_GetDatetime(XAMHandle inHandle, string inName, StringBuilder outValue);
    
        [DllImport("xam.dll")]
        public static extern int XAM_CreateXStream(XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inType, out XStreamHandle outXStream);
        
        [DllImport("xam.dll")]
        public static extern int XAM_OpenXStream(XAMHandle inHandle, string inName, string inMode, out XStreamHandle outXStream);
        
        [DllImport("xam.dll")]
        public static extern int XSystem_Close(XSystemHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XSystem_CreateXSet (XSystemHandle inHandle, string inMode, out XSetHandle outXSet);

        [DllImport("xam.dll")]
        public static extern int XSystem_CopyXSet(XSystemHandle inHandle, byte[] inXUID, string inMode, out XSetHandle outXSet);

        [DllImport("xam.dll")]
        public static extern int XSystem_OpenXSet (XSystemHandle inHandle, byte[] inXUID, string inMode, out XSetHandle outXSet);

        [DllImport("xam.dll")]
        public static extern int XSystem_DeleteXSet(XSystemHandle inHandle, byte[] inXUID);

        [DllImport("xam.dll")]
        public static extern int XSystem_IsXSetRetained(XSystemHandle inHandle, byte[] inXUID, [MarshalAs(UnmanagedType.U1)] out bool outRetained);

        [DllImport("xam.dll")]
        public static extern int XSystem_HoldXSet(XSystemHandle inHandle, byte[] inXUID, string inHoldID);

        [DllImport("xam.dll")]
        public static extern int XSystem_ReleaseXSet(XSystemHandle inHandle, byte[] inXUID, string inHoldID);

        [DllImport("xam.dll")]
        public static extern int XSystem_AccessXSet(XSystemHandle inHandle, byte[] inXUID, long inMode, [MarshalAs(UnmanagedType.U1)] out bool outAccessible);

        [DllImport("xam.dll")]
        public static extern int XSystem_GetXSetAccessTime(XSystemHandle inHandle, byte[] inXUID, StringBuilder outAccessTime);

        [DllImport("xam.dll")]
        public static extern int XSystem_Authenticate(XSystemHandle inHandle, string inBuffer, long inByteCount, out XStreamHandle outXStream);

        [DllImport("xam.dll")]
        public static extern int XIterator_Close(XIteratorHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XIterator_HasNext(XIteratorHandle inHandle, [MarshalAs(UnmanagedType.U1)] out bool outHasNext);

        [DllImport("xam.dll")]
        public static extern int XIterator_Next(XIteratorHandle inHandle, StringBuilder outNext);

        [DllImport("xam.dll")]
        public static extern int XSet_Commit(XSetHandle inHandle, byte[] outXUID);
        
        [DllImport("xam.dll")]
        public static extern int XSet_Close(XSetHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XSet_OpenExportXStream(XSetHandle inHandle, out XStreamHandle outXStream);

        [DllImport("xam.dll")]
        public static extern int XSet_OpenImportXStream(XSetHandle inHandle, out XStreamHandle outXStream);

        [DllImport("xam.dll")]
        public static extern int XSet_SubmitJob(XSetHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XSet_HaltJob(XSetHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XStream_Read(XStreamHandle inHandle, [MarshalAs(UnmanagedType.LPArray)] byte[] ioBuffer, long inBufferLength, out long outBytesRead);
        
        [DllImport("xam.dll")]
        public static extern int XStream_Write(XStreamHandle inHandle, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] byte[] inBuffer, long inByteCount, out long outBytesWritten);
        
        [DllImport("xam.dll")]
        public static extern int XStream_Seek(XStreamHandle inHandle, long inOffset, long inWhence);
        
        [DllImport("xam.dll")]
        public static extern int XStream_Tell(XStreamHandle inHandle, out long outPosition);
        
        [DllImport("xam.dll")]
        public static extern int XStream_Close(XStreamHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XStream_Abandon(XStreamHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XSystem_Abandon(XSystemHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XSet_Abandon(XSetHandle inHandle);

        // Retention

        [DllImport("xam.dll")]
        public static extern int XSet_SetBaseRetention(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, long inDuration);

        [DllImport("xam.dll")]
        public static extern int XSet_SetAutoDelete(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, [MarshalAs(UnmanagedType.U1)] bool inAutoDelete);

        [DllImport("xam.dll")]
        public static extern int XSet_GetActualAutoDelete(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] out bool outAutoDelete);

        [DllImport("xam.dll")]
        public static extern int XSet_SetShred(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, [MarshalAs(UnmanagedType.U1)] bool inShred);

        [DllImport("xam.dll")]
        public static extern int XSet_GetActualShred(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] out bool outShred);

        [DllImport("xam.dll")]
        public static extern int XSet_CreateRetention(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inRetentionID);

        [DllImport("xam.dll")]
        public static extern int XSet_SetRetentionEnabledFlag(XSetHandle inHandle, string inRetentionID, [MarshalAs(UnmanagedType.U1)] bool inBinding, [MarshalAs(UnmanagedType.U1)] bool inEnabled);

        [DllImport("xam.dll")]
        public static extern int XSet_SetRetentionDuration(XSetHandle inHandle, string inRetentionID, [MarshalAs(UnmanagedType.U1)] bool inBinding, long inDuration);

        [DllImport("xam.dll")]
        public static extern int XSet_SetRetentionStarttime(XSetHandle inHandle, string inRetentionID, [MarshalAs(UnmanagedType.U1)] bool inBinding);

        [DllImport("xam.dll")]
        public static extern int XSet_GetActualRetentionEnabled(XSetHandle inHandle, string inRetentionID, [MarshalAs(UnmanagedType.U1)] out bool outEnabled);

        [DllImport("xam.dll")]
        public static extern int XSet_GetActualRetentionDuration(XSetHandle inHandle, string inRetentionID, out long outDuration);

        [DllImport("xam.dll")]
        public static extern int XSet_ResetAccessFields(XSetHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XSet_ResetManagementFields(XSetHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XSet_ApplyAccessPolicy(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inPolicyName);

        [DllImport("xam.dll")]
        public static extern int XSet_ApplyManagementPolicy(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inPolicyName);

        [DllImport("xam.dll")]
        public static extern int XSet_ApplyRetentionEnabledPolicy(XSetHandle inHandle, string inRetentionID, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inPolicyName);

        [DllImport("xam.dll")]
        public static extern int XSet_ApplyRetentionDurationPolicy(XSetHandle inHandle, string inRetentionID, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inPolicyName);

        [DllImport("xam.dll")]
        public static extern int XSet_ApplyBaseRetentionPolicy(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inPolicyName);

        [DllImport("xam.dll")]
        public static extern int XSet_ApplyAutoDeletePolicy(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inPolicyName);

        [DllImport("xam.dll")]
        public static extern int XSet_ApplyShredPolicy(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inPolicyName);

        [DllImport("xam.dll")]
        public static extern int XSet_ApplyStoragePolicy(XSetHandle inHandle, [MarshalAs(UnmanagedType.U1)] bool inBinding, string inPolicyName);

        // Async APIs
        [DllImport("xam.dll")]
        public static extern int XSystem_AsyncOpenXSet(XSystemHandle inHandle, byte[] inXUID, string inMode, long inID, XAsyncCallback inCallback, out XAsyncHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XSystem_AsyncCopyXSet(XSystemHandle inHandle, byte[] inXUID, string inMode, long inID, XAsyncCallback inCallback, out XAsyncHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XAM_AsyncOpenXStream(XAMHandle inHandle, string inName, string inMode, long inID, XAsyncCallback inCallback, out XAsyncHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XStream_AsyncWrite(XStreamHandle inHandle, byte[] inBuffer, long inBufferSize, long inID, XAsyncCallback inCallback, out XAsyncHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XStream_AsyncRead(XStreamHandle inHandle, byte[] inBuffer, long inBufferSize, long inID, XAsyncCallback inCallback, out XAsyncHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XStream_AsyncClose(XStreamHandle inHandle, long inID, XAsyncCallback inCallback, out XAsyncHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XSet_AsyncCommit(XSetHandle inHandle, long inID, XAsyncCallback inCallback, out XAsyncHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XAsync_Halt(XAsyncHandle inHandle);

        [DllImport("xam.dll")]
        public static extern int XAsync_IsComplete(XAsyncHandle inHandle, [MarshalAs(UnmanagedType.U1)] out bool outComplete);

        [DllImport("xam.dll")]
        public static extern int XAsync_GetStatus(XAsyncHandle inHandle, out int outStatus);

        [DllImport("xam.dll")]
        public static extern int XAsync_GetXOPID(XAsyncHandle inHandle, out long outXOPID);

        [DllImport("xam.dll")]
        public static extern int XAsync_GetXSet(XAsyncHandle inHandle, out XSetHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XAsync_GetXStream(XAsyncHandle inHandle, out XStreamHandle outHandle);

        [DllImport("xam.dll")]
        public static extern int XAsync_GetXUID(XAsyncHandle inHandle, byte[] outXUID);

        [DllImport("xam.dll")]
        public static extern int XAsync_GetBytesRead(XAsyncHandle inHandle, out long outRead);

        [DllImport("xam.dll")]
        public static extern int XAsync_GetBytesWritten(XAsyncHandle inHandle, out long outWritten);

        [DllImport("xam.dll")]
        public static extern int XAsync_Close(XAsyncHandle inHandle);

        // XAM Toolkit Imports
        [DllImport("xam_toolkit.dll")]
        public static extern int XAMToolkit_IsPropertyField (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] out bool outIsProperty);

        [DllImport("xam_toolkit.dll")]
        public static extern int XAMToolkit_IsXStreamField (XAMHandle inHandle, string inName, [MarshalAs(UnmanagedType.U1)] out bool outIsXStream);
        
        [DllImport("xam_toolkit.dll")]
        public static extern int XAMToolkit_XUIDtoString (byte[] inBinaryXUID, StringBuilder outStringXUID);
        
        [DllImport("xam_toolkit.dll")]
        public static extern int XAMToolkit_StringtoXUID (string inStringXUID, byte[] outBinaryXUID);
        
        [DllImport("xam_toolkit.dll")]
        public static extern int XAMToolkit_IsValidXUID (byte[] inBinaryXUID, [MarshalAs(UnmanagedType.U1)] out bool outIsValid);
    }

    public class Helpers
    {
        public static ASCIIEncoding encoder = new ASCIIEncoding();

        // Helper functions
        public static void CheckAndThrow(int inStatus, string inUserMessage)
        {
            CheckAndThrow(Constants.XAM_LIBRARY_HANDLE, inStatus, inUserMessage);
        }

        internal static void CheckAndThrow(XAMHandle inHandle, int inStatus, string inUserMessage)
        {
            if (0 != inStatus)
            {
                XAMException e = new XAMException(inHandle, inStatus, inUserMessage);
                throw e;
            }
        }

        internal static void CheckAndThrow(XSystemHandle inHandle, int inStatus, string inUserMessage)
        {
            CheckAndThrow((XAMHandle)inHandle, inStatus, inUserMessage);
        }

        /// <summary>Abstract base class for MultipartXStream objects</summary>
        /// <remarks>
        ///    A MultipartXStream is like a regular XStream but it is split across multiple fields on a XAMObject.
        ///    Like an XStream, it is derived from a standard .NET Stream. Not all methods are implemented.
        /// </remarks>
        public abstract class MultipartXStream : Stream, IDisposable
        {
            #region Members
            internal XStream[] streams;
            protected long virtualLength = 0;
            protected long virtualPosition = 0;
            protected int parts;
            protected bool direction;
            #endregion
            
            #region Properties

            protected int Parts { get { return streams.Length; } }

            protected long DefaultPartLength { get { return virtualLength / Parts; } }

            public override bool CanRead { get { return direction == Constants.OUTPUT_STREAM; } }

            public override bool CanSeek { get { return direction == Constants.OUTPUT_STREAM; } }

            public override bool CanWrite { get { return direction == Constants.INPUT_STREAM; } }

            public override long Length { get { return virtualLength; } }

            public override long Position
            {
                get { return virtualPosition; }
                set { throw new NotImplementedException(); }
            }

            #endregion

            #region Methods

            /// <summary>
            /// Disposes the underyling XStream objects.
            /// </summary>
            void IDisposable.Dispose()
            {
                int i;

                for (i = 0; i < streams.Length; i++)
                    streams[i].Dispose();

                GC.SuppressFinalize(this);
            }

            /// <summary>
            /// Queries the Length of an underlying XStream part of a the MultipartXStream.
            /// </summary>
            /// <param name="partNumber">the number of the underlying XStream part to be examined.</param>
            /// <returns>The length of an underlying XStream part.</returns>
            internal long PartLength(int partNumber)
            {
                if (partNumber != (Parts - 1))
                    return virtualLength / Parts;
                else
                    return virtualLength - ((Parts - 1) * (virtualLength / Parts));
            }

            /// <summary>
            /// Queries the slice and slice offset for a given absoloute (conceptual) position within a MultipartXStream.
            /// </summary>
            /// <param name="absolute">the absolute position in the MultipartXStream.</param>
            /// <param name="slice">the index of the underlying XStream part.</param>
            /// <param name="offset">the offset within the underlying XStream part.</param>
            protected void SlicePosition(long absolute, out int slice, out long offset)
            {
                slice = (int)(absolute / DefaultPartLength);

                if (slice == Parts)
                    slice--;

                offset = (int)(absolute - (slice * DefaultPartLength));
            }

            /// <summary>
            /// Queries the slice and slice offset for the current position within a MultipartXStream.
            /// </summary>
            /// <param name="slice">the index of the underlying XStream part.</param>
            /// <param name="offset">the offset within the underlying XStream part.</param>
            protected void SlicePosition(out int slice, out long offset) { SlicePosition(virtualPosition, out slice, out offset); }

            /// <summary>
            /// Writes data to the MultipartXStream at the current position - not implemented unless overridden in the deriving class.
            /// </summary>
            /// <param name="buffer">data to be written.</param>
            /// <param name="offset">offset in the buffer to start writing data from.</param>
            /// <param name="count">nummber of bytes to write.</param>
            public override void Write(byte[] buffer, int offset, int count)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Reads data from the MultipartXStream at the current position - not implemented unless overridden in the deriving class.
            /// </summary>
            /// <param name="buffer">container for data read.</param>
            /// <param name="offset">offset in the buffer to start writing the data that is read.</param>
            /// <param name="count">number of bytes to attempt to read.</param>
            /// <returns>The number of bytes actually read.</returns>
            public override int Read(byte[] buffer, int offset, int count)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Seeks to a position in the MultipartXStream - not implemented unless overridden in the deriving class.
            /// </summary>
            /// <param name="offset">offset to Seek to.</param>
            /// <param name="origin">origin to seek from.</param>
            /// <returns>The resulting position in the MultipartXstream.</returns>
            public override long Seek(long offset, SeekOrigin origin)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Flushes the MultipartXStream - not implemented.
            /// </summary>
            public override void Flush()
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Sets the new length of q MultipartXStream - not implemented.
            /// </summary>
            public override void SetLength(long value)
            {
                throw new NotImplementedException();
            }
            #endregion
        }

        /// <summary>Represents an object that is used for writing a MultipartXStream of a XAMObject.</summary>
        /// <remarks>
        ///    The size and number of parts comprising the MultipartXStream must be specified on creation.
        ///    Private constructor as these objects are created by a factory method on the XAMObject.
        /// </remarks>
        public class MultipartInputXStream : MultipartXStream
        {
            #region Constructors
            /// <summary>
            /// Internal constructor called by the XAMObject factory method.
            /// </summary>
            /// <param name="s">An array of XStreams created by the factory method.</param>
            /// <param name="sz">The length of the input data.</param>
            internal MultipartInputXStream(XStream[] s, long sz)
            {
                streams = s;
                virtualLength = sz;
                parts = streams.Length;
                direction = Constants.INPUT_STREAM;
            }
            #endregion
            #region Methods
            /// <summary>
            /// Writes data to the MultipartXStream at the current position.
            /// </summary>
            /// <param name="buffer">data to be written.</param>
            /// <param name="offset">offset in the buffer to start writing data from.</param>
            /// <param name="count">nummber of bytes to write.</param>
            public override void Write(byte[] buffer, int offset, int count)
            {
                int startSlice = 0, endSlice = 0;
                long sliceOffset = 0;

                if (buffer.Length < (count + offset))
                    count = buffer.Length - offset;

                if (virtualPosition + count > virtualLength)
                    count = (int) (virtualLength - virtualPosition);

                SlicePosition(out startSlice, out sliceOffset);
                SlicePosition( virtualPosition + count, out endSlice, out sliceOffset);

                if (startSlice == endSlice)
                    streams[startSlice].Write(buffer, offset, count);
                else
                {
                    int partialWrite = 0;
                    int totalWritten = 0;

                    do
                    {
                        if (startSlice < endSlice)
                            partialWrite = (int)((DefaultPartLength * (startSlice + 1)) - virtualPosition);
                        else
                            partialWrite = count - totalWritten;

                        streams[startSlice++].Write(buffer, offset + totalWritten, partialWrite);
                        totalWritten += partialWrite;
                        virtualPosition += partialWrite;

                    } while (totalWritten < count);
                }
            }
            #endregion
        }

        /// <summary>Represents an object that is used for reading a MultipartXStream of a XAMObject.</summary>
        /// <remarks>
        ///    The class virtualizes the multiple XStream objects into a single XStream. The class user
        ///    does not need to be aware of the number of parts.
        ///    Private constructor as these objects are opened by a factory method on the XAMObject.
        /// </remarks>
        public class MultipartOutputXStream : MultipartXStream
        {
            #region Constructors
            /// <summary>Internal constructor called by the XAMObject factory method when opening an existing MultipartXStream.</summary>
            /// <param name="s">An array of XStreams created by the factory method.</param>
            internal MultipartOutputXStream(XStream[] s)
            {
                int i = 0;
                streams = s;
                parts = streams.Length;
                direction = Constants.OUTPUT_STREAM;

                for (i = 0; i < streams.Length; i++)
                    virtualLength += streams[i].Length;
            }
            #endregion
            #region Methods
            /// <summary>
            /// Seeks to a position in the MultipartXStream.
            /// </summary>
            /// <param name="offset">offset to Seek to.</param>
            /// <param name="origin">origin to seek from.</param>
            /// <returns>The resulting position in the MultipartXstream.</returns>
            public override long Seek(long offset, SeekOrigin origin)
            {
                int slice = 0;
                long absolute = 0;

                switch (origin)
                {
                    case SeekOrigin.Begin: absolute = offset;
                        break;

                    case SeekOrigin.Current: absolute = virtualPosition + offset;
                        break;

                    case SeekOrigin.End: absolute = virtualLength - offset;
                        break;
                }

                // What is the  slice / offset for the absolute position?               
                SlicePosition(absolute, out slice, out offset);

                streams[slice].Seek(offset, SeekOrigin.Begin);
                virtualPosition = absolute;

                return virtualPosition;
            }

            /// <summary>
            /// Reads data from the MultipartXStream at the current position.
            /// </summary>
            /// <param name="buffer">container for data read.</param>
            /// <param name="offset">offset in the buffer to start writing the data that is read.</param>
            /// <param name="count">number of bytes to attempt to read.</param>
            /// <returns>The number of bytes actually read.</returns>
            public override int Read(byte[] buffer, int offset, int count)
            {
                int bytesRead = 0, startSlice = 0, endSlice = 0;
                long sliceOffset = 0;

                if (buffer.Length < (offset + count))
                    count = buffer.Length - offset;

                if (virtualPosition + count > virtualLength)
                    count = (int)(virtualLength - virtualPosition);

                // Get out the slice offset and count for the start and end of the read
                SlicePosition(out startSlice, out sliceOffset); 

                SlicePosition(virtualPosition + count, out endSlice, out sliceOffset);

                if (startSlice == endSlice)
                {
                    // All bytes are in the same segment;
                    bytesRead = streams[startSlice].Read(buffer, offset, count);
                    virtualPosition += bytesRead;
                }
                else
                {
                    // We are reading bytes from multiple slices
                    int partialRead = 0;
                    byte[] myBuffer = new byte[count];
                    int myOffset = 0;

                    do
                    {
                        if (startSlice < endSlice)
                            partialRead = (int)((DefaultPartLength * (startSlice + 1)) - virtualPosition);
                        else
                            // Last slice can be bigger so read all that we need
                            partialRead = count - myOffset;

                        bytesRead = streams[startSlice++].Read(myBuffer, myOffset, partialRead);
                        myOffset += bytesRead;
                        virtualPosition += bytesRead;
                    } while (bytesRead == partialRead && startSlice <= endSlice);

                    bytesRead = myOffset;
                    Array.Copy(myBuffer, 0, buffer, offset, bytesRead);
                }
                return bytesRead;
            }
            #endregion
        }
    }

    /// <summary>
    /// The Exception type thrown on encountering errors when calling the underlying C API calls..
    /// </summary>
    [Serializable]
    public class XAMException : Exception
    {
        #region Constructors
        /// <summary>
        /// Internal constructor when error is detected.
        /// </summary>
        /// <param name="inHandle">The XAMLibrary object to obtain the error details from.</param>
        /// <param name="inStatus">Error code to be generated - normally the return status of the API operation.</param>
        /// <param name="inUserMessage">String containing user supplied context information.</param>
        internal XAMException(XAMHandle inHandle, int inStatus, string inUserMessage)
        {
            status = inStatus;
            userMessage = inUserMessage;
            StringBuilder sb = new StringBuilder(Constants.STRING_SZ);
            if (Imports.XAM_GetErrorToken(inHandle, inStatus, sb))
            {
                errorToken = sb.ToString();
            }
        }

        /// <summary>
        /// Public constructor for creating instances of XAM Exceptions when user determines that something is wrong based
        /// on the return status on the XAMLibrary instance.
        /// </summary>
        /// <param name="inStatus">Error code to be generated.</param>
        /// <param name="inUserMessage">String containing user supplied context information</param>
        public XAMException(int inStatus, string inUserMessage) : this(Constants.XAM_LIBRARY_HANDLE, inStatus, inUserMessage) { }

        protected XAMException(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) {}

        #endregion

        #region Methods
        /// <summary>
        /// Construct a meaningful error message containg textual description.
        /// </summary>
        /// <returns>The string representation of the XAMException.</returns>
        public override string ToString()
        {
            string errorString = "XAM Error <" + Status + ">";
            if (null != ErrorToken)
            {
                errorString += ": \"" + ErrorToken + "\"";
            }
            if (null != UserMessage)
            {
                errorString += " [" + UserMessage + "]";
            }
            return errorString;
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
            {
                throw new ArgumentNullException("info");
            }

            info.AddValue("Status", status);
            info.AddValue("ErrorToken", errorToken);
            info.AddValue("UserMessage", userMessage);

            base.GetObjectData(info, context);
        }
        #endregion

        #region Properties
        /// <summary>
        /// The error status code of the XAMException.
        /// </summary>
        public int Status { get { return status; } }

        /// <summary>
        /// The descption of the XAMException error status.
        /// </summary>
        public string ErrorToken { get { return errorToken; } }

        /// <summary>
        /// User supplied context information
        /// </summary>
        public string UserMessage { get { return userMessage; } }
        #endregion

        private int status = 0;
        private string errorToken = null;
        private string userMessage = null;
    }

    /// <summary>
    /// Facilitates Enumeration of the fields of a XAMObject.
    /// </summary>
    public class XIterator : IEnumerator, IDisposable
    {
        protected bool disposed = false;
        XIteratorHandle ith;
        XString current = new XString();
        string pattern;
        XAMHandle xamHandle;

        #region Constructors
        /// <summary>
        /// Internal constructor called by the factory method of the XAMObject containing the fields.
        /// </summary>
        /// <param name="h">XAMHandle of the XAMObject.</param>
        /// <param name="s">pattern to match on.</param>
        internal XIterator(XAMHandle h, string s)
        {
            pattern = s;
            xamHandle = h;
            Open();
        }
        #endregion
        
        #region Methods

        /// <summary>
        /// Opens the field iterator.
        /// </summary>
        private void Open()
        {
            int retval = Imports.XAM_OpenFieldIterator(xamHandle, pattern, out ith);
            Helpers.CheckAndThrow(retval, "XAM_OpenFieldIterator");
        }

        /// <summary>
        /// Closes the field iterator explicitly.
        /// </summary>
        protected void Close()
        {
            int retval = Imports.XIterator_Close(ith);
            Helpers.CheckAndThrow(retval, "Xiterator_Close");
        }
        #endregion

        #region Properties

        /// <summary>
        /// The next object of the iterator - in our case the name of the field.
        /// </summary>
        internal XString Next
        {
            get
            {
                int retval = Imports.XIterator_Next(ith, current);
                Helpers.CheckAndThrow(retval, "XIterator_Next");

                return current;
            }
        }

        /// <summary>
        /// Does the iterator have more objects available?
        /// </summary>
        internal bool HasNext
        {
            get
            {
                bool hasNext = false;

                int retval = Imports.XIterator_HasNext(ith, out hasNext);
                Helpers.CheckAndThrow(retval, "XIterator_HasNext");

                return hasNext;
            }
        }

        #endregion
        
        #region IEnumerator
        /// <summary>
        /// Move the iterator back to the start
        /// </summary>
        public void Reset()
        {
            int retval = Imports.XIterator_Close(ith);
            Helpers.CheckAndThrow(retval, "XIterator_Close");

            Open();
        }

        /// <summary>
        /// Advance the iterator (sets current to the next object).
        /// </summary>
        /// <returns>False if there are no more objects</returns>
        public bool MoveNext()
        {
            if (HasNext)
            {
                current = Next;
                return true;
            }
            else
                return false;
        }

        /// <summary>
        /// Get the current object of the iterator
        /// </summary>
        public object Current
        {
            get
            {
                return current;
            }
        }

        #endregion

        #region IDisposable
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public void Dispose(bool disposing)
        {
            if (!disposed)
            {
                disposed = true;
                // Cleanup any unmanaged objects - in this case, the XIteratorHandle
                Close();
            }
        }
        #endregion
    }

    /// <summary>Object representing the "attributes" of a XAMObject field</summary>
    /// <remarks>
    ///    Convenience class to easily GET the attributes of a field (cannot be midified).
    /// </remarks>
    public class XFieldInfo: IDisposable
    {
        XAMHandle xamHandle;
        XString name = new XString(), type = new XString();
        long length = 0;
        bool binding = false, readOnly = false;

        #region IDisposable
        protected bool disposed = false;
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        // The "disposing" boolean allows derived objects to add an additional step to dispose
        // of any IDisposable objects they own dependent on who is calling it i.e. diectly or via the dtor.
        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Cleanup managed objects
                name.Dispose();
                type.Dispose();
            }

            if (!disposed)
            {
                // Cleanup any unmanaged objects
                disposed = true;
            }
        }
        #endregion

        #region Constructors

        /// <summary>
        /// Internal constructor called by the factory method of the XAMObject on which the field is located.
        /// </summary>
        /// <param name="xh">The XAMHandle of the XAMObject containing the field.</param>
        /// <param name="n">The name of the field.</param>
        internal XFieldInfo(XAMHandle xh, XString n)
        {
            xamHandle = xh;
            name = n;
            int retval = Imports.XAM_GetFieldType(xh, name, type);
            Helpers.CheckAndThrow(retval, "XAM_GetField");

            retval = Imports.XAM_GetFieldReadOnly(xh, name, out readOnly);
            Helpers.CheckAndThrow(retval, "XAM_GetFieldReadOnly");

            length = Length;
            binding = Binding;
        }
        #endregion
        #region Methods

        /// <summary>
        /// Concatenate the attriubtes to provide a full representation of the Field.
        /// </summary>
        /// <returns>The string representing the attributes of the field</returns>
        public override string ToString()
        {
            return "Field " + Name + ": " + Type + " " + Value + " (" + Length + ") Binding (" + Binding + ") ReadOnly (" + ReadOnly + ")";
        }
        #endregion

        #region Properties

        /// <summary>
        /// The Name of the field
        /// </summary>
        public XString Name { get { return name; } }

        /// <summary>
        /// The SNIA type of the field.
        /// </summary>
        public XString Type { get { return type; } }

        /// <summary>
        /// The "mofifiable" staus of the field i.e. is ir writable or ReadOnly
        /// </summary>
        public bool ReadOnly { get { return readOnly; } }

        /// <summary>
        /// Is the field binding or non-binding?
        /// </summary>
        public bool Binding
        {
            get
            {
                int retval = Imports.XAM_GetFieldBinding(xamHandle, name, out binding);
                Helpers.CheckAndThrow(retval, "XAM_GetFieldBinding");

                return binding;
            }
        }

        /// <summary>
        /// The length of the field.
        /// </summary>
        public long Length
        {
            get
            {
                int retval = Imports.XAM_GetFieldLength(xamHandle, name, out length);
                Helpers.CheckAndThrow(retval, "XAM_GetFieldLength");

                return length;
            }
        }

        /// <summary>
        /// Is the field a Property (not an XStream)?
        /// </summary>
        public bool Property
        {
            get
            {
                bool type = false;
                int retval = Imports.XAMToolkit_IsPropertyField(xamHandle, name, out type);

                return type;
            }
        }

        /// <summary>
        /// Is the field an XStream (not a Property)?
        /// </summary>
        public bool XStream { get { return !Property;  } }

        /// <summary>
        /// The value of a Boolean field.
        /// </summary>
        private bool BoolValue
        {
            get
            {
                bool value = false;
                int retval = Imports.XAM_GetBoolean(xamHandle, name, out value);
                Helpers.CheckAndThrow(retval, "XAM_GetBoolean");

                return value;
            }
        }

        /// <summary>
        /// The value of an Int field.
        /// </summary>
        private long IntValue
        {
            get
            {
                long value;

                int retval = Imports.XAM_GetInt(xamHandle, name, out value);
                Helpers.CheckAndThrow(retval, "XAM_GetInt");

                return value;
            }
        }

        /// <summary>
        /// The value of a XUID field.
        /// </summary>
        private XUID XUIDValue
        {
            get
            {
                XUID value = new XUID();

                int retval = Imports.XAM_GetXUID(xamHandle, name, value);
                Helpers.CheckAndThrow(retval, "XAM_GetXUID");

                return value;
            }
        }

        /// <summary>
        /// The value of a Double field.
        /// </summary>
        private double DoubleValue
        {
            get
            {
                double value = 0;

                int retval = Imports.XAM_GetDouble(xamHandle, name, out value);
                Helpers.CheckAndThrow(retval, "XAM_GetDouble");

                return value;
            }
        }

        /// <summary>
        /// The value of an XString field.
        /// </summary>
        private XString XStringValue
        {
            get
            {
                XString value = new XString();

                int retval = Imports.XAM_GetString(xamHandle, name, value);
                Helpers.CheckAndThrow(retval, "XAM_GetString");

                return value;
            }
        }

        /// <summary>
        /// The value of a DateTime field.
        /// </summary>
        private DateTime DatetimeValue
        {
            get
            {
                XString value = new XString();

                int retval = Imports.XAM_GetDatetime(xamHandle, name, value);
                Helpers.CheckAndThrow(retval, "XAM_GetDatetime");

                return DateTime.Parse(value);
            }
        }
     
        /// <summary>
        /// An object representing the underlying value of the field (can be cast to the "real" value by using the Type).
        /// </summary>
        public object Value
        {
            get
            {
                object value = null;

                if (Property)
                {
                    switch (Type.ToString()[25])
                    {
                        case 'b':
                            value = BoolValue;
                            break;

                        case 'i':
                            value = IntValue;
                            break;

                        case 'd':
                            // Could be a double or a Datetime field
                            if (Type.ToString()[26] == 'o')
                                value = DoubleValue;
                            else
                                value = DatetimeValue;
                            break;

                        case 's':
                            value = XStringValue;
                            break;

                        case 'x':
                            value = XUIDValue;
                            break;
                    }
                }
                else
                    value = new XString("XStream of length " + Length);

                return value;
            }
        }
        #endregion
    }
}
